from copy import deepcopy
from tkinter import StringVar, Listbox
from tkinter.simpledialog import Dialog
from tkinter.ttk import Frame, Button, Label, Entry
from .edit_tag import TagDialog
from .style import PADDING
from .event_bus import Event, ETYPE_TAG_CHANGED, ETYPE_BOOKMARK_CHANGED, register_handler, send_event
from ..store.bookmark import Bookmark, EMPTY_BOOKMARK, add_bookmark, update_bookmark
from ..store.bookmark import get_bookmark_by_name
from ..store.tag import list_tags, get_tag_by_id, get_tag_by_name

PADDING_D_2 = PADDING // 2

class BookmarkDialog(Dialog):
    def __init__(self, parent, old_bookmark: Bookmark = EMPTY_BOOKMARK):
        self.old_bookmark = deepcopy(old_bookmark)
        super().__init__(parent, "添加书签" if self.is_adding_bookmark else "编辑书签")
    
    @property
    def is_adding_bookmark(self):
        return self.old_bookmark.uid < 0
    
    def body(self, _master):
        self.resizable(False, False)
        box = Frame(self)
        # 书签名字
        frame = Frame(box)
        label = Label(frame, text="书签名称")
        label.pack(side="left", padx=(0, PADDING_D_2))
        self.bmk_name_var = StringVar()
        self.bmk_name_var.set(self.old_bookmark.name)
        bmk_name = Entry(frame, width=64, textvariable=self.bmk_name_var)
        bmk_name.pack(side="right")
        frame.pack(side="top", padx=PADDING, pady=(PADDING, 0), fill="x")
        # 书签内容
        frame = Frame(box)
        label = Label(frame, text="书签内容")
        label.pack(side="left", padx=(0, PADDING_D_2))
        self.bmk_value_var = StringVar()
        self.bmk_value_var.set(self.old_bookmark.value)
        bmk_value = Entry(frame, width=64, textvariable=self.bmk_value_var)
        bmk_value.pack(side="right")
        frame.pack(side="top", padx=PADDING, pady=(PADDING, 0), fill="x")
        # 书签标签
        frame = Frame(box)
        # = 左侧已选标签
        frame_tag_panel = Frame(frame)
        text_tag_panel = Label(frame_tag_panel, text="已选标签")
        text_tag_panel.pack(side="top", padx=0, pady=0, fill="x")
        self.list_tags_left = Listbox(frame_tag_panel, width=26)
        self.list_tags_left.pack(side="top", padx=0, pady=0, fill="both")
        self.list_tags_left.bind("<Double-Button-1>", self.delete_tag)
        frame_tag_panel.pack(side="left", padx=0, pady=0, expand=0)
        # = 左侧已选标签 end
        # = 右侧未选标签
        frame_tag_panel = Frame(frame)
        text_tag_panel = Label(frame_tag_panel, text="未选标签")
        text_tag_panel.pack(side="top", padx=0, pady=0, fill="x")
        self.list_tags_right = Listbox(frame_tag_panel, width=26)
        self.list_tags_right.pack(side="top", padx=0, pady=0, fill="both")
        self.list_tags_right.bind("<Double-Button-1>", self.add_tag)
        frame_tag_panel.pack(side="right", padx=0, pady=0, expand=0)
        # = 右侧未选标签 end
        # = 中间操作按钮
        frame_tag_panel = Frame(frame)
        text_tag_panel = Label(frame_tag_panel, text=" ")
        text_tag_panel.pack(side="top", padx=0, pady=0, fill="x")
        btn_tag_add_new = Button(frame_tag_panel, text="添加新标签", command=self.add_new_tag)
        btn_tag_add_new.pack(side="top", padx=0, pady=(0, PADDING))
        btn_tag_add = Button(frame_tag_panel, text="←添加标签", command=self.add_tag)
        btn_tag_add.pack(side="top", padx=0, pady=(PADDING, 0))
        btn_tag_remove = Button(frame_tag_panel, text="→删除标签", command=self.delete_tag)
        btn_tag_remove.pack(side="top", padx=0, pady=(PADDING, 0))
        frame_tag_panel.pack(side="top", padx=0, pady=(PADDING, 0), fill="y")
        # = 中间操作按钮 end
        frame.pack(side="top", padx=PADDING, pady=0, fill="x")
        box.pack(side="top")
        self.update_tag_list()
        register_handler(self.on_event)

    def buttonbox(self):
        box = Frame(self)
        w = Button(box, text="保存", width=10, command=self.ok, default="active")
        w.pack(side="left", padx=PADDING_D_2, pady=(0, PADDING))
        w = Button(box, text="取消", width=10, command=self.cancel)
        w.pack(side="right", padx=PADDING_D_2, pady=(0, PADDING))
        box.pack()
        pass

    def on_event(self, evt: Event):
        if evt.t == ETYPE_TAG_CHANGED:
            self.update_tag_list()

    def update_tag_list(self):
        remain_tags_set = set(( tag.uid for tag in list_tags() ))
        has_tags_set = self.old_bookmark.tags
        remain_tags = list(filter(
            None,
            ( get_tag_by_id(tag_uid) for tag_uid in (remain_tags_set - has_tags_set) ),
        ))
        has_tags = list(filter(
            None,
            ( get_tag_by_id(tag_uid) for tag_uid in has_tags_set ),
        ))
        remain_tags.sort(key=lambda tag: tag.uid)
        has_tags.sort(key=lambda tag: tag.uid)
        self.list_tags_left.delete(0, self.list_tags_left.size() - 1)
        self.list_tags_right.delete(0, self.list_tags_right.size() - 1)
        for tag in has_tags:
            self.list_tags_left.insert(self.list_tags_left.size(), tag.name)
        for tag in remain_tags:
            self.list_tags_right.insert(self.list_tags_right.size(), tag.name)

    def validate(self):
        name = self.bmk_name_var.get().strip()
        if len(name) <= 0:
            #名字为空
            return False
        if self.is_adding_bookmark:
            if get_bookmark_by_name(name):
                # 名字已经存在了
                return False
        return True
    
    def apply(self):
        bmk = Bookmark()
        bmk.uid = self.old_bookmark.uid
        bmk.name = self.bmk_name_var.get().strip()
        bmk.value = self.bmk_value_var.get().strip()
        bmk.tags = self.old_bookmark.tags
        if self.is_adding_bookmark:
            add_bookmark(bmk)
        else:
            update_bookmark(bmk)
        send_event(Event(t=ETYPE_BOOKMARK_CHANGED))
    
    # ======== ↓按钮的回调方法↓ ========
    def add_new_tag(self, _event=None):
        dlg = TagDialog(self) # block until closed
    
    def add_tag(self, _event=None):
        if self.list_tags_right.curselection():
            name = self.list_tags_right.get(self.list_tags_right.curselection()[0])
            tag = get_tag_by_name(name)
            self.old_bookmark.tags.add(tag.uid)
            self.update_tag_list()
    
    def delete_tag(self, _event=None):
        if self.list_tags_left.curselection():
            name = self.list_tags_left.get(self.list_tags_left.curselection()[0])
            tag = get_tag_by_name(name)
            self.old_bookmark.tags.discard(tag.uid)
            self.update_tag_list()